iT邦幫忙

2021 iThome 鐵人賽

DAY 14
0
Modern Web

每日挑戰,從Javascript面試題目了解一些你可能忽略的概念系列 第 14

每日挑戰,從Javascript面試題目了解一些你可能忽略的概念 - Day14

  • 分享至 

  • xImage
  •  
tags: ItIron2021 Javascript

前言

作者發燒中,但文章還是得發?
昨天的主題是關於js如何傳遞值,了解基本型別與物件間的差別是極端重要的概念,今天馬上來一個應用題目吧!

本日題目與解釋

請解釋在JS中你要如何拷貝一個物件或是一個陣列

thinking-day14

又是一個看起來很簡單但一時間你可能回答不出來的題目對吧? 當碰到比較困難的題目時,我會先試著把題目做簡化,我們先縮小題目的範圍吧!

請解釋在JS中你要如何拷貝一個陣列

有了昨天的教訓,我們都很清楚下方的寫法是會有問題的

let arr1 = [1, 2, 3]
let arr2 = arr1

這兩個玩意有著相同的reference,你修改一個、另一個也會同樣受到影響,所以這很明顯是出局的,以下有幾個常見的方法!

  • 迴圈

沒錯,就是你熟悉的for loop,這樣最基礎的做法往往最容易被人忽略

let arr1 = [1, 2, 3]
let arr2 = []
for (let i = 0; i < arr1.length; i++) {
  arr2.push(arr1[i])
}

同樣的道理,你當然也能用map或filter這樣的語法糖去複製一個陣列!

  • slice or concat

另一個切入的方向就是利用js原生的一些方法去做到直接複製的效果,上述的兩種方法也能很好的達成任務

let arr1 = [1, 2, 3]
let arr2 = [].concat(arr1)
let arr3 = arr1.slice()

arr2.push(4)
arr3.push(5)

console.log(arr1) // [1, 2, 3]
console.log(arr2) // [1, 2, 3, 4]
console.log(arr3) // [1, 2, 3, 5]

你可以看到三者確實已經是不同的reference了。

  • 擴展運算子(spread operator)

這玩意可說是我最喜歡的方法了,新加入的擴展運算子在許多地方都很實用,用來做陣列的複製與合併再適合不過了。

let arr1 = [1, 2, 3]
let arr2 = [...arr1] // [1, 2, 3]

這方法同樣也適用於物件的複製

let obj1 = {
  name: 'Danny',
  age: 30
}

let obj2 = {
  ...obj1
}

在我們繼續往下之前..你知道上述的方法有什麼問題嗎?

上述的幾種方法雖然都成功地複製了陣列/物件,但他們全都屬於所謂的淺拷貝(shallow clone),也就是說萬一你今天複製的對象裡面還有其他的物件,裡面的物件會還是保持同一個reference,我們看個簡單的例子。

let demo = [0, [1, 2]]
let demoClone = demo.slice() // [0, [1, 2]]

demoClone[1].push(3)

console.log(demoClone) //  [0, [1, 2, 3]]
console.log(demo) //  [0, [1, 2, 3]]

上述的範例中雖然成功的複製了一維度的陣列,但裡面的物件仍保有相同的reference,造成了你看到的結果,為了解決這樣的問題,你需要的是深拷貝(deep clone),而在js中最簡單做到深拷貝的辦法就是先轉成json字串再parse回來,原理大致上是因為字串屬於基本型別,所以複製的時候會重新建立一個記憶體位置,其他的細節老樣子自己去查?

  • 深拷貝
let demo = [0, [1, 2]]
let demoClone = JSON.parse(JSON.stringify(demo))

demoClone[1].push(3)

console.log(demoClone) //  [0, [1, 2, 3]]
console.log(demo) //  [0, [1, 2]]

你可以看到,這麼一來連裡面的物件參照也完全不同囉! 但這個方法有個小缺陷,由於是要轉成json再轉成字串儲存,你原先的內容就要是合法的json數值,萬一裡面包含著函數就會直接掰掰了,這種時候你就要想辦法去處理深拷貝囉! 但處理面試只要能回答以上幾個方向基本上就完全沒有問題了!

物件與陣列的複製方式都很接近,也就是迴圈、型別既有語法以及擴展運算子,最終的大殺招就是轉json字串再轉回來做的深拷貝。

本日核心觀念與總結

核心觀念

深拷貝 vs 淺拷貝、擴展運算子

總結

  • 了解複製陣列或物件的幾種方法
  • 了解深淺拷貝間的差異
  • 了解轉json字串的限制

本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!


上一篇
每日挑戰,從Javascript面試題目了解一些你可能忽略的概念 - Day13
下一篇
每日挑戰,從Javascript面試題目了解一些你可能忽略的概念 - Day15
系列文
每日挑戰,從Javascript面試題目了解一些你可能忽略的概念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言